home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 46
/
Amiga Format CD46 (1999-10-20)(Future Publishing)(GB)[!][issue 1999-12].iso
/
-in_the_mag-
/
reader_requests
/
pdflib
/
p_font.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-09-16
|
14KB
|
483 lines
/* p_font.c
* Copyright (C) 1997-98 Thomas Merz. All rights reserved.
*
* PDFlib font embedding routines
*/
#include <string.h>
#include "p_intern.h"
#include "afmparse.h"
#include "ansi_e.h"
#include "macrom_e.h"
#include "pdfdoc_e.h"
#define MAXFILENAME 256
#define LINEBUFLEN 256
/* Bit positions for font descriptor flag */
#define FIXEDWIDTH (long) (1L<<0)
#define SERIF (long) (1L<<1)
#define SYMBOL (long) (1L<<2)
#define SCRIPT (long) (1L<<3)
#define ADOBESTANDARD (long) (1L<<5)
#define ITALIC (long) (1L<<6)
#define SMALLCAPS (long) (1L<<17)
#define FORCEBOLD (long) (1L<<18)
/* dummy values for stem width */
#define DEFAULT_STEMWIDTH 75
#define DEFAULT_STEMWIDTH_SEMI 105
#define DEFAULT_STEMWIDTH_BOLD 130
/* PDF's base 14 fonts, guaranteed to be always available */
const char *pdf_base14fonts[] = {
"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
"Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique",
"Symbol",
"Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
"ZapfDingbats",
NULL
};
const char *pdf_encoding_names[encoding_count] = {
NULL, "PDFDocEncoding", "MacRomanEncoding",
"MacExpertEncoding", "WinAnsiEncoding"
};
PDF_encodingvector *pdf_encoding[encoding_count] = {
NULL, &pdf_pdfdoc, &pdf_macroman, NULL, &pdf_winansi
};
/* Type 1 font portions: ASCII, encrypted, zeros */
typedef enum { ascii, encrypted, zeros } pdf_t1portion;
typedef struct {
pdf_t1portion portion;
long length1, length2, length3;
FILE *fontfile;
} t1_private_data;
static void
t1data_init(PDF *p, PDF_data_source *src)
{
t1_private_data *t1_private;
t1_private = (t1_private_data *) src->private_data;
t1_private->portion = ascii;
t1_private->length1 = 0;
t1_private->length2 = 0;
t1_private->length3 = 0;
src->buffer_start = (byte *) PDF_malloc(LINEBUFLEN, "t1data_init");
src->buffer_length = LINEBUFLEN;
}
static bool
t1data_fill(PDF *p, PDF_data_source *src)
{
static const char HexToBin[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0,
10, 11, 12, 13, 14, 15 };
char *s, *c;
int i;
t1_private_data *t1_private;
t1_private = (t1_private_data *) src->private_data;
if ((s = fgets((char *) src->buffer_start, LINEBUFLEN,
t1_private->fontfile))== NULL)
return false;
/* check for line of zeros: set zero flag if found */
for (c = s; *c == '0'; c++)
;
if (*c == '\n')
t1_private->portion = zeros;
src->next_byte = src->buffer_start;
switch (t1_private->portion) {
case ascii:
t1_private->length1 += strlen(s);
src->bytes_available = strlen(s);
break;
case encrypted:
t1_private->length2 += strlen(s)/2; /* ASCII -> binary */
src->bytes_available = strlen(s)/2;
/* convert ASCII to binary in-place */
for (i=0; s[i] != '\n'; i += 2)
{
if (s[i] < '0' || s[i] > 'F' || s[i+1] < '0' || s[i+1] > 'F')
pdf_error(p, PDF_WARN,
"Bogus Type 1 font ASCII data (%c, %c)", s[i], s[i+1]);
s[i/2] = 16*HexToBin[s[i] - '0'] + HexToBin[s[i+1] - '0'];
}
break;
case zeros:
t1_private->length3 += strlen(s);
src->bytes_available = strlen(s);
break;
}
if (t1_private->portion != encrypted &&
!strncmp((const char *)s, "currentfile eexec", 17))
t1_private->portion = encrypted;
return true;
}
static void
t1data_terminate(PDF *p, PDF_data_source *src)
{
PDF_free((void *) src->buffer_start);
}
float
PDF_stringwidth(PDF *p, byte *text)
{
byte *cp;
float width = 0.0;
for (cp = text; *cp; cp++)
width += p->current_font->size * p->current_font->FontWidths[*cp]/1000;
return width;
}
bool
pdf_read_afm(PDF *p, char *fontname, PDF_encoding enc)
{
FILE *afmfile;
int *widths;
FontInfo *fi;
int i, j;
char filename[MAXFILENAME], *charname;
CharMetricInfo *cmi;
/* HACK */
widths = p->current_font->FontWidths;
/* check for afm file */
sprintf(filename, "%s.afm", fontname);
/* try current directory */
afmfile = fopen(filename, "r");
if (afmfile == NULL && p->info->fontpath) {
/* try font path if caller supplied one */
sprintf(filename, "%s%s%s.afm", p->info->fontpath, PATHSEP, fontname);
afmfile = fopen(filename, "r");
}
if (afmfile == NULL) {
pdf_error(p, PDF_WARN, "Couldn't open AFM file for font %s", fontname);
return false;
}
/* parse AFM file */
if (pdf_parseFile(afmfile, &fi, P_G | P_M) != ok) {
fclose(afmfile);
pdf_error(p, PDF_FATAL, "Error parsing AFM file %s", filename);
return false;
}
fclose(afmfile);
if (fi->cmi == NULL) {
pdf_error(p, PDF_FATAL,
"Couldn't parse char metrics in AFM file %s", filename);
return false;
}
/*
* Generate character width array according to chosen encoding vector
* or the font's default encoding vector.
*/
if (enc != builtin &&
strcmp(fi->gfi->encodingScheme, "AdobeStandardEncoding")) {
pdf_error(p, PDF_WARN,
"Symbol font %s doesn't use builtin encoding", fontname);
}
if (enc == builtin &&
!strcmp(fi->gfi->encodingScheme, "AdobeStandardEncoding")) {
pdf_error(p, PDF_WARN, "Text font %s uses builtin encoding",
fontname);
enc = builtin;
}
if (enc != builtin && pdf_encoding[enc]) {
for (i = 0; i < 256; i++) { /* text font */
charname = (*pdf_encoding[enc])[i];
widths[i] = 0;
if (charname == NULL) /* unencoded character */
continue;
for (j = 0, cmi = fi->cmi; j < fi->numOfChars; ++j, ++cmi) {
if (!strcmp(cmi->name, charname)) {
widths[i] = cmi->wx;
break;
}
}
}
} else { /* symbol or pi font */
for (i = 0; i < 256; i++)
widths[i] = 0;
for (i = 0, cmi = fi->cmi; i < fi->numOfChars; i++, cmi++) {
if (cmi->code >= 0 && cmi->code < 256)
widths[cmi->code] = cmi->wx;
}
}
/* HACK */
/* copy relevant data to current_font struct */
p->current_font->ascender = fi->gfi->ascender;
p->current_font->descender = fi->gfi->descender;
p->current_font->capHeight = fi->gfi->capHeight;
p->current_font->isFixedPitch = fi->gfi->isFixedPitch;
p->current_font->italicAngle = fi->gfi->italicAngle;
p->current_font->llx = fi->gfi->fontBBox.llx;
p->current_font->lly = fi->gfi->fontBBox.lly;
p->current_font->urx = fi->gfi->fontBBox.urx;
p->current_font->ury = fi->gfi->fontBBox.ury;
p->current_font->StdVW = fi->gfi->StdVW;
p->current_font->StdHW = fi->gfi->StdHW;
p->current_font->underlinePosition = fi->gfi->underlinePosition;
p->current_font->underlineThickness = fi->gfi->underlineThickness;
strcpy(p->current_font->fontName, fi->gfi->fontName);
strcpy(p->current_font->encodingScheme, fi->gfi->encodingScheme);
strcpy(p->current_font->weight, fi->gfi->weight);
/*
* If we don't know the exact stem width we use default values
* according to the font weight (regular, semi, or bold)
*/
if (p->current_font->StdVW == 0) {
if (!strcmp(p->current_font->weight, "Semibold"))
p->current_font->StdVW = DEFAULT_STEMWIDTH_SEMI;
else if (!strcmp(p->current_font->weight, "Bold"))
p->current_font->StdVW = DEFAULT_STEMWIDTH_BOLD;
else
p->current_font->StdVW = DEFAULT_STEMWIDTH;
}
/* free AFM parser's storage */
freeStorage(fi);
return true;
}
void
pdf_put_t1font(PDF *p, char *fontname, id font_id, int fontnumber, bool embed)
{
FILE *fontfile = NULL;
char filename[MAXFILENAME];
int *widths;
int i, j;
unsigned long fontflags;
id fontdescriptor_id, fontfile_id = 0l;
id length_id, length1_id, length2_id, length3_id;
long length, stream_start;
PDF_data_source t1src;
const char **cp;
PDF_encoding enc;
enc = p->current_font->encoding;
/* Should use font cache instead */
if (!pdf_read_afm(p, fontname, enc)) { /* HACK */
pdf_error(p, PDF_FATAL, "Couldn't read metrics for font %s", fontname);
return;
}
widths = p->current_font->FontWidths;
/* check whether we have one of the base 14 fonts */
for (cp = pdf_base14fonts; *cp; ++cp)
if (!strcmp(*cp, fontname)) {
pdf_begin_obj(p, font_id);
pdf_begin_dict(p);
(void) fputs("/Type /Font\n", p->fp);
(void) fputs("/Subtype /Type1\n", p->fp);
(void) fprintf(p->fp, "/Name /F%d\n", fontnumber);
if (enc != builtin) {
(void) fprintf(p->fp, "/Encoding /%s\n",
pdf_encoding_names[enc]);
}
(void) fprintf(p->fp, "/BaseFont /%s\n", *cp);
pdf_end_dict(p);
pdf_end_obj(p); /* font */
return;
}
/* check for font file */
strcpy(filename, fontname);
if (embed) {
/* try current directory */
fontfile = fopen(filename, "r");
if (fontfile == NULL && p->info->fontpath) {
/* try font path if caller supplied one */
sprintf(filename, "%s%s%s", p->info->fontpath, PATHSEP, fontname);
fontfile = fopen(filename, "r");
}
if (fontfile == NULL) {
pdf_error(p, PDF_WARN, "Couldn't open font file %s", filename);
embed = false;
}
}
/* Section 7.5: Font attributes */
pdf_begin_obj(p, font_id);
pdf_begin_dict(p);
(void) fputs("/Type /Font\n", p->fp);
(void) fputs("/Subtype /Type1\n", p->fp);
(void) fprintf(p->fp, "/Name /F%d\n", fontnumber);
(void) fputs("/FirstChar 0\n", p->fp);
(void) fputs("/LastChar 255\n", p->fp);
(void) fputs("/Widths [\n", p->fp);
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++)
(void) fprintf(p->fp, " %d", widths[16*i + j]);
(void) fputs("\n", p->fp);
}
(void) fputs("]\n", p->fp);
if (enc != builtin) {
(void) fprintf(p->fp, "/Encoding /%s\n",
pdf_encoding_names[enc]);
}
(void) fprintf(p->fp, "/BaseFont /%s\n", fontname);
fontdescriptor_id = pdf_alloc_id(p);
(void) fprintf(p->fp, "/FontDescriptor %ld 0 R\n", fontdescriptor_id);
pdf_end_dict(p);
pdf_end_obj(p); /* font */
/* Section 7.8: font descriptors */
pdf_begin_obj(p, fontdescriptor_id);
pdf_begin_dict(p);
(void) fputs( "/Type /FontDescriptor\n", p->fp);
(void) fprintf(p->fp, "/Ascent %d\n", p->current_font->ascender);
(void) fprintf(p->fp, "/CapHeight %d\n", p->current_font->capHeight);
(void) fprintf(p->fp, "/Descent %d\n", p->current_font->descender);
fontflags = 0;
if (p->current_font->isFixedPitch)
fontflags |= FIXEDWIDTH;
if (!strcmp(p->current_font->encodingScheme, "AdobeStandardEncoding"))
fontflags |= ADOBESTANDARD;
else
fontflags |= SYMBOL;
if (p->current_font->italicAngle < 0)
fontflags |= ITALIC;
/* heuristic to identify (small) caps fonts */
if (strstr(fontname, "Caps") ||
!strcmp(fontname + strlen(fontname) - 2, "SC"))
fontflags |= SMALLCAPS;
/* this doesn't catch all cases but will do for the moment */
if (!strcmp(p->current_font->weight, "Bold"))
fontflags |= FORCEBOLD;
(void) fprintf(p->fp, "/Flags %ld\n", fontflags);
(void) fprintf(p->fp, "/FontBBox [%d %d %d %d ]\n",
p->current_font->llx, p->current_font->lly,
p->current_font->urx, p->current_font->ury);
(void) fprintf(p->fp, "/FontName /%s\n", fontname);
(void) fprintf(p->fp, "/ItalicAngle %d\n",
(int) (p->current_font->italicAngle));
(void) fprintf(p->fp, "/StemV %d\n", p->current_font->StdVW);
if (embed) {
fontfile_id = pdf_alloc_id(p);
(void) fprintf(p->fp, "/FontFile %ld 0 R\n", fontfile_id);
}
pdf_end_dict(p);
pdf_end_obj(p); /* font descriptor */
/* Section 7.8.1: font files */
if (embed) {
pdf_begin_obj(p, fontfile_id);
pdf_begin_dict(p);
if (p->info->binary_mode == false)
(void) fputs("/Filter /ASCIIHexDecode\n", p->fp);
length_id = pdf_alloc_id(p);
length1_id = pdf_alloc_id(p);
length2_id = pdf_alloc_id(p);
length3_id = pdf_alloc_id(p);
(void) fprintf(p->fp, "/Length %ld 0 R\n", length_id);
(void) fprintf(p->fp, "/Length1 %ld 0 R\n", length1_id);
(void) fprintf(p->fp, "/Length2 %ld 0 R\n", length2_id);
(void) fprintf(p->fp, "/Length3 %ld 0 R\n", length3_id);
/* Don't omit zeros since more data may follow at the end! */
pdf_end_dict(p);
pdf_begin_stream(p); /* font data stream */
stream_start = ftell(p->fp);
t1src.init = t1data_init;
t1src.fill = t1data_fill;
t1src.terminate = t1data_terminate;
t1src.private_data = (unsigned char *)
PDF_malloc(sizeof(t1_private_data), "pdf_put_t1font");
((t1_private_data *) t1src.private_data)->fontfile = fontfile;
if (p->info->binary_mode) {
t1src.init(p, &t1src);
while (t1src.fill(p, &t1src))
(void) fwrite(t1src.next_byte, 1, t1src.bytes_available, p->fp);
t1src.terminate(p, &t1src);
} else
pdf_ASCIIHexEncode(p, &t1src);
length = ftell(p->fp) - stream_start;
pdf_end_stream(p);
pdf_end_obj(p); /* font file object */
pdf_begin_obj(p, length_id); /* Length object */
(void) fprintf(p->fp,"%ld\n", length);
pdf_end_obj(p);
pdf_begin_obj(p, length1_id); /* Length1 object */
(void) fprintf(p->fp,"%ld\n",
((t1_private_data *) t1src.private_data)->length1);
pdf_end_obj(p);
pdf_begin_obj(p, length2_id); /* Length2 object */
(void) fprintf(p->fp,"%ld\n",
((t1_private_data *) t1src.private_data)->length2);
pdf_end_obj(p);
pdf_begin_obj(p, length3_id); /* Length3 object */
(void) fprintf(p->fp,"%ld\n",
((t1_private_data *) t1src.private_data)->length3);
pdf_end_obj(p);
fclose(((t1_private_data *) t1src.private_data)->fontfile);
PDF_free((void *) t1src.private_data);
}
}